using System;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Unity.Extensions;
using Xunit;

namespace Unity.Extensions
{
    public class InterceptRemotingInterceptionExtensionTest
    {
        [Fact]
        public void InterceptViaAttributes()
        {
            Recorder.Records.Clear();
            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<InterceptionExtension>();

            SpyMBROWithAttribute obj = container.Resolve<SpyMBROWithAttribute>();
            obj.InterceptedMethod();

            Assert.Equal(3, Recorder.Records.Count);
            Assert.Equal("Before Method", Recorder.Records[0]);
            Assert.Equal("In Method", Recorder.Records[1]);
            Assert.Equal("After Method", Recorder.Records[2]);
        }

        [Fact]
        public void InterceptViaCode()
        {
            Recorder.Records.Clear();
            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<InterceptionExtension>();
            container.Configure<IInterceptionConfiguration>().InterceptRemoting<SpyMBRO>(typeof(SpyMBRO).GetMethod("InterceptedMethod"),
                                                                                         new RecordingHandler());

            SpyMBRO obj = container.Resolve<SpyMBRO>();
            obj.InterceptedMethod();

            Assert.Equal(3, Recorder.Records.Count);
            Assert.Equal("Before Method", Recorder.Records[0]);
            Assert.Equal("In Method", Recorder.Records[1]);
            Assert.Equal("After Method", Recorder.Records[2]);
        }

        [Fact]
        public void InterfacesNotSupported()
        {
            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<InterceptionExtension>();
            container.RegisterType<ISpy, SpyInterfaceImplWithAttribute>();

            Assert.Throws<ResolutionFailedException>(() => container.Resolve<ISpy>());
        }

        internal interface ISpy
        {
            void InterceptedMethod();
        }

        internal class SpyInterfaceImplWithAttribute : ISpy, IBuilderAware
        {
            [RemotingIntercept(typeof(RecordingHandler))]
            public void InterceptedMethod()
            {
                Recorder.Records.Add("In Method");
            }

            public void OnBuiltUp(object buildKey)
            {
                Recorder.Records.Add("OnBuiltUp");
            }

            public void OnTearingDown()
            {
                Recorder.Records.Add("OnTearingDown");
            }
        }

        internal class SpyMBRO : MarshalByRefObject
        {
            public void InterceptedMethod()
            {
                Recorder.Records.Add("In Method");
            }
        }

        internal class SpyMBROWithAttribute : MarshalByRefObject
        {
            [RemotingIntercept(typeof(RecordingHandler))]
            public void InterceptedMethod()
            {
                Recorder.Records.Add("In Method");
            }
        }
    }
}